﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;

namespace FunctionalLayer
{
    /// <summary>
    /// Used store the settings
    /// </summary>
    public class ConfigSingleton
    {

        #region Fields
        private static ConfigSingleton _config;

        public static ConfigSingleton Settings
        {
            get { return _config ?? (_config = new ConfigSingleton()); }
            set { ConfigSingleton._config = value; }
        }
        #endregion

        public static event Action<string> ExceptionOccured;
        
        /// <summary>
        /// Constructor
        /// </summary>
        private ConfigSingleton()
        { }

        #region Hardware
        //Circumference of the wheel
        public double WheelCircumference;

        //Arduino port for e.g. COM1
        public string ArduinoPort;

        //Xbee port for e.g. COM1
        public string XBeePort;

        //8-bits: 1 byte so 1024 combinations from 0 to 1023 of Arduino
        internal double MinVal = 0.00;
        internal double MaxVal = 1023.00;
        internal double CombiVal = 1024.00;
        #endregion

        #region Software
        // Max race time.
        private TimeSpan _maxRaceTime;
        // Public Property - XmlIgnore as it doesn't serialize anyway
        [XmlIgnore]
        public TimeSpan MaxRaceTime
        {
            get { return _maxRaceTime; }
            set { _maxRaceTime = value; }
        }

        // Pretend property for serialization
        [XmlElement("MaxRaceTime")]
        public long TicksMaxRaceTime
        {
            get { return _maxRaceTime.Ticks; }
            set { _maxRaceTime = new TimeSpan(value); }
        }

        //Number of laps
        public int Laps;

        //Sections per lap
        public int SectionsPerLap;

        //Total lap distance in meters
        public double LapDistance;

        //Location of the log file
        public string LogFilePath;
        
        //Location of the error log file
        public string LogFilePathError;

        #endregion

        /// <summary>
        /// Deserialize/ Import XML Config file to object
        /// </summary>
        /// <typeparam name="T">Type of Object to serialize</typeparam>
        /// <param name="fileText">The text/ information of the file</param>
        /// <returns>Deserialize object</returns>
        public static T Import<T>(string fileText)
        {
            try
            {
                T result;
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                TextReader tr = new StreamReader(fileText);
                result = (T)serializer.Deserialize(tr);
                return result;
            }
            catch (System.Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    ExceptionOccured(ex.Message);
                }
                return default(T);
            }

        }

        /// <summary>
        /// Serializes/ Export the data in the object to the designated file path
        /// </summary>
        /// <typeparam name="T">Type of Object to serialize</typeparam>
        /// <param name="dataToSerialize">Object to serialize</param>
        /// <param name="filePath">FilePath for the XML file</param>
        /// <returns>Returns true if the export is successfulg</returns>
        public static bool Export<T>(T dataToSerialize, string filePath)
        {
            try
            {
                Stream stream = File.Open(filePath, FileMode.Create, FileAccess.ReadWrite);
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                XmlTextWriter writer = new XmlTextWriter(stream, Encoding.Default);
                serializer.Serialize(writer, dataToSerialize);
                writer.Close();
                return true;
            }
            catch (Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    ExceptionOccured(ex.Message);    
                }
                return false;
            }
        }
    }
}